#define RUNTIME_DBG_LVL			2
#include <dbg/ptest.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <metalc/base/mtls.h>
#include <metalc/mlos/mmapheap.h>
#include <pthreadalt.h>


#include "apds_common.h"
#include <unix/page_alloc_os.h>

/* 定义wfspan */
// #define WFSPAN_MBLOCK		(SIZE_2M)		/* 归还给操作系统的MBLOCK基本单位 */
#include <metalc/mlayer/wfspan.h>
DEF_CLS_SUPER_CLS2SZTBL(super, 4, 15, MANTISSA_BITS_DEFAULT, LOW_BITS_DEFAULT)

SIN hword_t unitsz2maxnr(szcls_t cls){
	/* 提前算好的, 39个map映射表 */
	static const uint16_t maptable[] = {4088, 2044, 1362, 1022, 817, 681, 584, 511, 408, 340, 292, 255, 204, 170, 146, 127, 102, 85, 73, 63, 51, 42, 36, 31, 25, 21, 18, 15, 12, 10, 9, 7, 6, 5, 4, 3, 3, 2, 2};
	ASSERT(cls < _clsnr_super);
	return (hword_t)maptable[cls];
}

DEF_WFSLAB_MLAYER(wfspan, 4, 15, BIT(16), 41, 0, 1, super, unitsz2maxnr, mlcc_palloc)

/* 定义seglf */
#include <metalc/mlayer/segfit_lf.h>
SAI void mark_used(void *ptr, size_t size){
	os_commit(ptr, size);
}
SAI void mark_unused(void *ptr, size_t size){
	os_decommit_lazy(ptr, size, 1);
}
DEF_SEGLF_2B_MLAYER(seglf_bin_ext, 16, HDEF_PTR_BITS, SIZE_4K, mark_used, mark_unused, mlcc_palloc, page_alloc)

/* mmap heap*/
DEF_MMAPHEAP_MLAYER(mmapheap_normal, 2 * 1024 * 1024, SIZE_1G, SIZE_64G, 0, 0)
/* 组合 */
COMPOSE_MLAYER(test_wfspan, wfspan, seglf_bin_ext, mmapheap_normal)

/* 定义tls */
DEF_MTLS_PTHREAD(GET_MLAYER_OBJNR(test_wfspan), 4096, mlcc_palloc, mp_coreid)

/* 定义初始化过程 */
#include <pthreadalt/pthreadalt_init.h>
DEF_PTHREADALT_INIT
DEF_SYSINIT(mtls, testnode, test_wfspan)
DEF_CFLOWFIN(mtls)
DEF_CFLOWINIT(mtls, test_wfspan)
DEF_SYSFIN(__omega)

/* 测试 */

#define TEST_MAXTHREADS	(24)
#define TEST_NR		(1000000)

#define TEST_MINSIZE	(1)
#define TEST_MAXSIZE	(256)
#define TEST_SET	(1)
#define TEST_ALLOC	test_wfspan_alloc
#define TEST_FREE	test_wfspan_free
#define TEST_SIZEOF	test_wfspan_sizeof


static void *bench_wfspan(void *args){
	PARAM_USED(args);
	mreq_t req;
	for (word_t idx = 0; idx < TEST_NR; idx++){
		size_t rqsize = TEST_MINSIZE + hash(idx + rdcnt_relax()) % (TEST_MAXSIZE - TEST_MINSIZE);
		mreq_setalloc(&req, rqsize, 0);
		uvoid *umem = TEST_ALLOC(&req);
		void *mem = req.ptr;
		// assert(umem);
		
		assert(umem);
		req.ptr = umem;
		size_t size = TEST_SIZEOF(&req);
		assert(size >= rqsize);
		PARAM_USED(umem, mem, size);
		if (TEST_SET) {
			__memset(umem, 0xff, rqsize);
			// INFO("memset [%p - %p]\n", umem, umem + usize);
		}
		req.nr = 1;
		TEST_FREE(&req);
	}
	return NULL;
}
PERF_PARALLEL_FUNC_THREADNR(bench_wfspan, TEST_NR * 2, TEST_MAXTHREADS)

void test_wfspan_basic(){
	mreq_t req;
	void *mem;
	mreq_setalloc(&req, 16, 0);
	mem = test_wfspan_alloc(&req);

	req.ptr = mem;
	size_t sz = test_wfspan_sizeof(&req);
	assert(sz >= 16);

	bool_t s = test_wfspan_free(&req);
	assert(s == TRUE);

}
static void test_wfspan_end(){
	dbg_printf("wfspan bench ok\n");
}
/* perf测试 */
int main(){
	test_wfspan_basic();
	dbg_printf("now bench wfspan\n");
	PERF_PARALLEL_RUN(bench_wfspan);
	test_wfspan_end();
	return 0;
}